#ifndef __filter_count_hpp_lkjjwfejiojoiwef93323290i98u9hy7yf43jifejji2efjnvnjv__
#define __filter_count_hpp_lkjjwfejiojoiwef93323290i98u9hy7yf43jifejji2efjnvnjv__

#include <functional>

namespace hude
{
	namespace utils
	{
		
		/**********************************************************************************************
		 * @brief filter_count_t
		 */
		template< typename _VALUE >
		class filter_count_t
		{
		public:
			enum range_t : int { emRANG_UP = 1, emRANG_IN = 0, emRANG_DOWN = -1 };
			typedef _VALUE value_t;
			typedef filter_count_t< value_t > this_t;
			typedef std::function< void( const this_t& ) > handle_t;

		public:
			filter_count_t() : up_( value_t() ), down_( value_t() ),
				current_( value_t() ), state_( emRANG_IN ) { _set( current_ ); }

			filter_count_t( value_t u, value_t d, value_t c, handle_t l = handle_t(),
				handle_t s = handle_t() ) : up_( u ), down_( d ), current_( c ),
				handle_liment_( l ), handle_step_( s ), state_( emRANG_IN ) { _set( current_ ); }

			filter_count_t( const filter_count_t& v ) : up_( v.up() ), down_( v.down() ),
				current_( value_t() ), handle_liment_( v.liment() ), handle_step_( v.step() ),
				state_( emRANG_IN ) { _set( current_ ); }

			const filter_count_t& operator=( const filter_count_t& v ) {
				return handle_liment_ = v.liment(), handle_step_ = v.step(),
					_set( v.up(), v.down(), v.current() ), *this; }

			value_t range( value_t v )
			{
				if( v > up_ ) v = up_;
				if( v < down_ ) v = down_;

				return v;
			}

			value_t up() const { return up_; }
			void up( value_t v ) { up_ = v; }

			value_t down() const { return down_; }
			void down( value_t v ) { down_ = v; }

			value_t current() const { return current_; }
			void current( value_t v ) { current_ = range( v ); }

			handle_t liment() const { return handle_liment_; }
			void liment( handle_t v ) { handle_liment_ = v; }

			handle_t step() const { return handle_step_; }
			void step( handle_t v ) { handle_step_ = v; }

			range_t range() const { return state_; }

			range_t set_add( value_t v = 1 ) { return _set( current_ + v ); }
			range_t set_dec( value_t v = 1 ) { return _set( current_ - v ); }
			range_t set_current( value_t v ) { return _set( v ); }

		private:
			range_t _set( value_t u, value_t d, value_t c ) { return up_ = u, down_ = d, _set( c ); }

			range_t _set( value_t v )
			{
				v = range( v );
				range_t r = _comp( v );
				current_ = v;
				return r;
			}

			range_t _comp( value_t v )
			{
				state_ = emRANG_IN;

				if( v == up_ )
				{
					state_ = emRANG_UP;

					if( current_ < up_ && handle_liment_ ) handle_liment_( *this );
				} else  if( v == down_ ) {
					state_ = emRANG_DOWN;

					if( current_ > down_ && handle_liment_ ) handle_liment_( *this );
				}

				if( handle_step_ ) handle_step_( *this );

				return state_;
			}

		private:
			value_t up_, down_, current_;
			handle_t handle_liment_, handle_step_;
			range_t state_;

		};
		
	} //namespace utils
} //namespace hude

#endif //__filter_count_hpp_lkjjwfejiojoiwef93323290i98u9hy7yf43jifejji2efjnvnjv__
